﻿using Microsoft.Practices.Unity;
using Albatross.SSRSViewer.ReportSvcs;
using Albatross.WPF.Common;
using Albatross.WPF.Common.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.ServiceModel.Configuration;
using System.Text;
using System.Threading.Tasks;

namespace Albatross.SSRSViewer.ViewModels {
	public class ReportViewerViewModel : WorkspaceViewModel {
		public string Server { get; private set; }
		public ReportViewerViewModel(string server) {
			Title = string.Format("Reports@{0}", server);
			Server = server;
			Items = new ObservableCollection<ReportItemViewModel>();
			GetReportServerUri();
			ShowEmptyFolder = false;
			ShowOther = false;
			ShowReport = true;
			ShowDataSource = false;
		}

		#region properties
		public ObservableCollection<ReportItemViewModel> Items { get; private set; }
		public Uri ReportServerUri {
			get;
			private set;
		}
		public const string ShowDataSourcePropertyName = "ShowDataSource";
		private bool _showDataSource;
		public bool ShowDataSource {
			get { return _showDataSource; }
			set {
				if (_showDataSource == value) { return; }
				RaisePropertyChanging(ShowDataSourcePropertyName);
				_showDataSource = value;
				RaisePropertyChanged(ShowDataSourcePropertyName);
				SetVisibility(Items);
			}
		}
		public const string ShowReportPropertyName = "ShowReport";
		private bool _showReport;
		public bool ShowReport {
			get { return _showReport; }
			set {
				if (_showReport == value) { return; }
				RaisePropertyChanging(ShowReportPropertyName);
				_showReport = value;
				RaisePropertyChanged(ShowReportPropertyName);
				SetVisibility(Items);
			}
		}
		public const string ShowOtherPropertyName = "ShowOther";
		private bool _showOther;
		public bool ShowOther {
			get { return _showOther; }
			set {
				if (_showOther == value) { return; }
				RaisePropertyChanging(ShowOtherPropertyName);
				_showOther = value;
				RaisePropertyChanged(ShowOtherPropertyName);
				SetVisibility(Items);
			}
		}
		public const string ShowEmptyFolderPropertyName = "ShowEmptyFolder";
		private bool _showEmptyFolder;
		public bool ShowEmptyFolder {
			get { return _showEmptyFolder; }
			set {
				if (_showEmptyFolder == value) { return; }
				RaisePropertyChanging(ShowEmptyFolderPropertyName);
				_showEmptyFolder = value;
				RaisePropertyChanged(ShowEmptyFolderPropertyName);
				SetVisibility(Items);
			}
		}
		public const string FilterPropertyName = "Filter";
		private string _filter;
		public string Filter {
			get { return _filter; }
			set {
				if (_filter == value) { return; }
				RaisePropertyChanging(FilterPropertyName);
				_filter = value;
				RaisePropertyChanged(FilterPropertyName);
				SetVisibility(Items);
				ExpandAll(null);
			}
		}
		#endregion

		#region methods
		public async override void LoadAsync(WPF.Common.IViewService svcs) {
			try {
				IsLoading = true;
				Items.Clear();
				Task<List<ReportItemViewModel>> task = Task<List<ReportItemViewModel>>.Run(() => {
					using (ReportSvcs.ReportingService2010SoapClient client = new ReportSvcs.ReportingService2010SoapClient(Server)) {
						client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

						ReportSvcs.CatalogItem[] items;
						ReportSvcs.ServerInfoHeader header = client.ListChildren(new ReportSvcs.TrustedUserHeader(), "/", true, out items);

						List<ReportItemViewModel> list = new List<ReportItemViewModel>();

						Dictionary<string, ReportItemViewModel> dict = new Dictionary<string, ReportItemViewModel>();
						foreach (var item in items) {
							ReportItemViewModel vm = new ReportItemViewModel().Set(item);
							if (string.IsNullOrEmpty(vm.Parent)) { list.Add(vm); }
							dict.Add(item.Path, vm);
						}
						foreach (var item in dict.Values) {
							ReportItemViewModel parent;
							if (dict.TryGetValue(item.Parent, out parent)) {
								parent.Children.Add(item);
							}
						}
						SetVisibility(list);
						return list;
					}
				});

				var rootItems = await task;
				foreach (var item in rootItems) {
					Items.Add(item);
				}

			} catch (Exception err) {
				svcs.ShowErrorMessageBox(err.Message);
			} finally {
				IsLoading = false;
			}
		}
		void GetReportServerUri() {
			ClientSection section = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
			foreach (ChannelEndpointElement ep in section.Endpoints) {
				if (ep.Name == Server) {
					string address = ep.Address.AbsoluteUri;
					int index = address.LastIndexOf("/");
					ReportServerUri = new Uri(address.Substring(0, index));
					break;
				}
			}
		}
		void SetVisibility(IEnumerable<ReportItemViewModel> items) {
			if (items != null) {
				foreach (var child in items) {
					child.SetVisibility(_showEmptyFolder, _showReport, _showDataSource, _showOther, _filter);
				}
			}
		}
		#endregion

		#region commands
		public RelayCommand<IViewService> ClearFilterCommand { get { return new RelayCommand<IViewService>(ClearFilter); } }
		void ClearFilter(IViewService svcs) {
			Filter = null;
		}
		public RelayCommand<IViewService> ExpandAllCommand { get { return new RelayCommand<IViewService>(ExpandAll); } }
		void ExpandAll(IViewService svcs) {
			try {
				foreach (ReportItemViewModel vm in Items) {
					vm.ExpandCollapse(true, true);
				}
			} catch (Exception err) {
				if(svcs != null) svcs.ShowErrorMessageBox(err.Message);
			}
		}
		public RelayCommand<IViewService> CollapseAllCommand { get { return new RelayCommand<IViewService>(CollapseAll); } }
		void CollapseAll(IViewService svcs) {
			try {
				foreach (ReportItemViewModel vm in Items) {
					vm.ExpandCollapse(false, true);
				}
			} catch (Exception err) {
				svcs.ShowErrorMessageBox(err.Message);
			}
		}
		public RelayCommand<IViewService> RefreshCommand { get { return new RelayCommand<IViewService>(Refresh); } }
		void Refresh(IViewService svcs) {
			LoadAsync(svcs);
		}
		#endregion
	}
}
